package com.codegeek.project.communicate;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.codegeek.framework.redis.RedisCache;
import com.codegeek.project.slope.domain.SlopeMonitorItem;
import com.codegeek.project.slope.domain.SlopeSensor;
import com.codegeek.project.slope.service.ISlopeSensorService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author wj
 * @ClassName
 * @Description
 * @date 2020-03-19
 */
@Configuration
@EnableScheduling
@RestController
public class SlopeGNSSService {

    private static String url;
    private static String authenAddr;
    private static String getDataAddr;

    private static String userName;
    private static String password;

    @Value("${GNSS.url}")
    public void GNSSUrl(String value){
        url = value;
    }
    @Value("${GNSS.authenAddr}")
    public void GNSSAuthenAddr(String value){
        authenAddr = value;
    }
    @Value("${GNSS.getDataAddr}")
    public void GNSSGetDataAddr(String value){
        getDataAddr = value;
    }
    @Value("${GNSS.userName}")
    public void GNSSUserName(String value){
        userName = value;
    }
    @Value("${GNSS.password}")
    public void GNSSPassword(String value){
        password = value;
    }

    String md5Passord;

    public static final Logger logger = LogManager.getLogger("FileUtils");

    @Autowired
    private ISlopeSensorService slopeSensorService;

    @Autowired
    RedisCache redisCache;

    @Autowired
    RedisDBService redisDBService;

    ExecutorService es = new ThreadPoolExecutor(50,100,10, TimeUnit.SECONDS,new LinkedBlockingQueue<>());

    @Scheduled(cron = "0 0/1 * * * ?")//主服务器
//    @Scheduled(cron = "30 0/1 * * * ? ")//从服务器
    public void getGNSSData() throws Exception {
        SlopeSensor sensor = new SlopeSensor();
        sensor.setSensorTypeId(redisDBService.getGNSSTypeId());
        List<SlopeSensor> list =  slopeSensorService.selectSlopeSensorList(sensor);
        es.execute(new GNSSDataCollectWork(list));
    }

    /**
     * @title
     * @description GNSS数据采集
     * @param
     * @return
     * @throws
     */
    private class GNSSDataCollectWork implements Runnable{
        List<SlopeSensor> deviceIds;

        public GNSSDataCollectWork(List<SlopeSensor> ids){
            this.deviceIds=ids;
        }

        @Override
        public void run() {
            String token= getToken();
            if(token!=null){
                getData(token);
            }
        }

        private class AuthInfo{
            private String userNameOrEmailAddress;
            private String password;
            private String clientType;

            public String getUserNameOrEmailAddress() {
                return userNameOrEmailAddress;
            }

            public void setUserNameOrEmailAddress(String userNameOrEmailAddress) {
                this.userNameOrEmailAddress = userNameOrEmailAddress;
            }

            public String getClientType() {
                return clientType;
            }

            public void setClientType(String clientType) {
                this.clientType = clientType;
            }

            public String getPassword() {
                return password;
            }

            public void setPassword(String password) {
                this.password = password;
            }
        }

        private String getToken(){
            try {
                if (md5Passord == null) {
                    md5Passord = DigestUtils.md5DigestAsHex(password.getBytes());
                }

                String tokenUrl = url + authenAddr;
                RestTemplate restTemplate = new RestTemplate();
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                JSONObject jsData=new JSONObject();
                jsData.put("userNameOrEmailAddress", userName);
                jsData.put("password", md5Passord);
                jsData.put("clientType", "web");
                AuthInfo authInfo=new AuthInfo();
                authInfo.setClientType("web");
                authInfo.setPassword(md5Passord);
                authInfo.setUserNameOrEmailAddress(userName);
                HttpEntity<AuthInfo> request = new HttpEntity<>(authInfo, headers);
                ResponseEntity<String> response = restTemplate.postForEntity(tokenUrl, request, String.class);

                JSONObject jsonObject= JSON.parseObject(response.getBody());
                String accessToken=jsonObject.getJSONObject("result").getString("accessToken");
                return accessToken;
            }
            catch (Exception e){
//                e.printStackTrace();
                logger.error(e);
                return null;
            }
        }

        private void getData(String authStr){
            Calendar calendar=Calendar.getInstance();
            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String endTime=sdf.format(calendar.getTime());
            calendar.add(Calendar.MINUTE,-60);              //每次读取前一个小时数据
            String startTime=sdf.format(calendar.getTime());
            String timeRange=startTime+" - "+endTime;
            String statisticsStyle="-1";                                //统计类型，实时
            for(SlopeSensor sensor:deviceIds){
                String id=sensor.getDevice().getImei();
                JSONObject data= requestData(timeRange,id,statisticsStyle,authStr);
                if(data!=null&&!data.isEmpty()){
                    Date lastDateTime=redisDBService.getSensorUpdateTime(id);
//                    Date thisTime=(Date)data.get("updateTime");
                    Date thisTime = new Date();
                    if(lastDateTime==null ||
                            (thisTime!=null&&!sdf.format(thisTime).equals(sdf.format(lastDateTime)))
                            ){
                        JSONObject jsSensor=data.getJSONObject("data");
                        redisDBService.addSensorHistoryData(id,thisTime,jsSensor);

                        for(SlopeMonitorItem monitorItem:sensor.getMonitorItems()){
                            redisDBService.alarmCheck(monitorItem,sensor.getDevice().getDeviceName(),sensor.getDevice().getNumber(),jsSensor.getFloat(monitorItem.getItemName()),sensor.getSensorId());
                            redisDBService.handleUpdateMoniterItem(monitorItem.getItemId(),jsSensor.getFloat(monitorItem.getItemName()));
                        }

                        redisDBService.updateSensorRealtime(id, thisTime,jsSensor);
                    }
                }
            }
        }

        private JSONObject requestData(String timeRange, String deviceId, String statisticsStyle, String authStr){
            try {
                String dataUrl = url + getDataAddr + "?timeRange=" + timeRange + "&deviceId=" + deviceId + "&statisticsStyle=" + statisticsStyle;
                RestTemplate restTemplate = new RestTemplate();
                HttpHeaders headers = new HttpHeaders();
                headers.setBearerAuth(authStr);
                Map<String, String> map = new HashMap<>();
                map.put("timeRange", timeRange);
                map.put("deviceId", deviceId);
                map.put("statisticsStyle", statisticsStyle);
                HttpEntity<String> entity = new HttpEntity(headers);
                ResponseEntity<String> response = restTemplate.exchange(dataUrl, HttpMethod.GET, entity, String.class);
                JSONObject jsData = JSONObject.parseObject(response.getBody());
                JSONArray series = jsData.getJSONArray("contents").getJSONObject(0).getJSONArray("series");
                JSONObject retData=new JSONObject();
                String time=null;
                for (int i = 0; i < series.size(); ++i) {
                    try {
                        JSONObject serie = series.getJSONObject(i);
                        String name = serie.getString("name");
                        JSONArray data = serie.getJSONArray("data");
                        Float lastData = data.getJSONArray(data.size() - 1).getFloat(1);
                        retData.put(name,lastData);
                        if(time==null){
                            time=data.getJSONArray(data.size() - 1).getString(0);
                        }
                    }catch (Exception e){
//                        logger.error(e);
                        throw new RuntimeException(e);
                    }
                }
                JSONObject retMap=new JSONObject();
                retMap.put("data",retData);
                retMap.put("updateTime",new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(time));
                return retMap;
            }catch (Exception e){
//                logger.error(e);
                return null;
            }
        }

    }

}
